﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using GraphicsFramework.Entity;
using GraphicsFramework.Property;
using System.Windows.Media;
using System.Windows.Input;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Shapes;

namespace CanvasWPF.Graphics
{
    class WPF : GraphicsFramework.GraphicsFramework
    {

        private UIElementCollection graphics;

        public WPF(int width, int height, int gridsize, GraphicsFramework.Entity.Point2F gridvalue)
            : base(width, height, gridsize, gridvalue)
        {
        }

        public override void SetGraphics(object graphics)
        {
            this.graphics = (UIElementCollection)graphics;

            this.graphics.Clear();
        }

        #region Device Conversion

        public override GraphicsFramework.Enum.EnumKeys GetKey(object e)
        {
            KeyEventArgs key = (KeyEventArgs)e;

            switch (key.Key)
            {
                //Numeric
                case Key.D0:
                case Key.NumPad0:
                    return GraphicsFramework.Enum.EnumKeys.Num0;
                case Key.D1:
                case Key.NumPad1:
                case Key.Oem1:
                    return GraphicsFramework.Enum.EnumKeys.Num1;
                case Key.D2:
                case Key.NumPad2:
                case Key.Oem2:
                    return GraphicsFramework.Enum.EnumKeys.Num2;
                case Key.D3:
                case Key.NumPad3:
                case Key.Oem3:
                    return GraphicsFramework.Enum.EnumKeys.Num3;
                case Key.D4:
                case Key.NumPad4:
                case Key.Oem4:
                    return GraphicsFramework.Enum.EnumKeys.Num4;
                case Key.D5:
                case Key.NumPad5:
                case Key.Oem5:
                    return GraphicsFramework.Enum.EnumKeys.Num5;
                case Key.D6:
                case Key.NumPad6:
                case Key.Oem6:
                    return GraphicsFramework.Enum.EnumKeys.Num6;
                case Key.D7:
                case Key.NumPad7:
                case Key.Oem7:
                    return GraphicsFramework.Enum.EnumKeys.Num7;
                case Key.D8:
                case Key.NumPad8:
                case Key.Oem8:
                    return GraphicsFramework.Enum.EnumKeys.Num8;
                case Key.D9:
                case Key.NumPad9:
                    return GraphicsFramework.Enum.EnumKeys.Num9;

                //Alphabets
                case Key.A:
                    return GraphicsFramework.Enum.EnumKeys.A;
                case Key.B:
                    return GraphicsFramework.Enum.EnumKeys.B;
                case Key.C:
                    return GraphicsFramework.Enum.EnumKeys.C;
                case Key.D:
                    return GraphicsFramework.Enum.EnumKeys.D;
                case Key.E:
                    return GraphicsFramework.Enum.EnumKeys.E;
                case Key.F:
                    return GraphicsFramework.Enum.EnumKeys.F;
                case Key.G:
                    return GraphicsFramework.Enum.EnumKeys.G;
                case Key.H:
                    return GraphicsFramework.Enum.EnumKeys.H;
                case Key.I:
                    return GraphicsFramework.Enum.EnumKeys.I;
                case Key.J:
                    return GraphicsFramework.Enum.EnumKeys.J;
                case Key.K:
                    return GraphicsFramework.Enum.EnumKeys.K;
                case Key.L:
                    return GraphicsFramework.Enum.EnumKeys.L;
                case Key.M:
                    return GraphicsFramework.Enum.EnumKeys.M;
                case Key.N:
                    return GraphicsFramework.Enum.EnumKeys.N;
                case Key.O:
                    return GraphicsFramework.Enum.EnumKeys.O;
                case Key.P:
                    return GraphicsFramework.Enum.EnumKeys.P;
                case Key.Q:
                    return GraphicsFramework.Enum.EnumKeys.Q;
                case Key.R:
                    return GraphicsFramework.Enum.EnumKeys.R;
                case Key.S:
                    return GraphicsFramework.Enum.EnumKeys.S;
                case Key.T:
                    return GraphicsFramework.Enum.EnumKeys.T;
                case Key.U:
                    return GraphicsFramework.Enum.EnumKeys.U;
                case Key.V:
                    return GraphicsFramework.Enum.EnumKeys.V;
                case Key.W:
                    return GraphicsFramework.Enum.EnumKeys.W;
                case Key.X:
                    return GraphicsFramework.Enum.EnumKeys.X;
                case Key.Y:
                    return GraphicsFramework.Enum.EnumKeys.Y;
                case Key.Z:
                    return GraphicsFramework.Enum.EnumKeys.Z;

                //Named Key
                case Key.Enter:
                    return GraphicsFramework.Enum.EnumKeys.Enter;
                case Key.Tab:
                    return GraphicsFramework.Enum.EnumKeys.Tab;
                case Key.Space:
                    return GraphicsFramework.Enum.EnumKeys.Space;
                case Key.Escape:
                    return GraphicsFramework.Enum.EnumKeys.Escape;
                case Key.PrintScreen:
                    return GraphicsFramework.Enum.EnumKeys.PrintScreen;
                case Key.Scroll:
                    return GraphicsFramework.Enum.EnumKeys.ScrollLock;
                case Key.Pause:
                    return GraphicsFramework.Enum.EnumKeys.Pause;
                case Key.Insert:
                    return GraphicsFramework.Enum.EnumKeys.Insert;
                case Key.Delete:
                    return GraphicsFramework.Enum.EnumKeys.Delete;
                case Key.Home:
                    return GraphicsFramework.Enum.EnumKeys.Home;
                case Key.End:
                    return GraphicsFramework.Enum.EnumKeys.End;
                case Key.PageUp:
                    return GraphicsFramework.Enum.EnumKeys.PageUp;
                case Key.PageDown:
                    return GraphicsFramework.Enum.EnumKeys.PageDown;

                //+, -, *, -
                case Key.Add:
                case Key.OemPlus:
                    return GraphicsFramework.Enum.EnumKeys.Add;
                case Key.Subtract:
                    return GraphicsFramework.Enum.EnumKeys.Subtract;
                case Key.OemMinus:
                    return GraphicsFramework.Enum.EnumKeys.Subtract;

                //Arrows
                case Key.Left:
                    return GraphicsFramework.Enum.EnumKeys.Left;
                case Key.Right:
                    return GraphicsFramework.Enum.EnumKeys.Right;
                case Key.Up:
                    return GraphicsFramework.Enum.EnumKeys.Up;
                case Key.Down:
                    return GraphicsFramework.Enum.EnumKeys.Down;

                //Functions
                case Key.F1:
                    return GraphicsFramework.Enum.EnumKeys.F1;
                case Key.F2:
                    return GraphicsFramework.Enum.EnumKeys.F2;
                case Key.F3:
                    return GraphicsFramework.Enum.EnumKeys.F3;
                case Key.F4:
                    return GraphicsFramework.Enum.EnumKeys.F4;
                case Key.F5:
                    return GraphicsFramework.Enum.EnumKeys.F5;
                case Key.F6:
                    return GraphicsFramework.Enum.EnumKeys.F6;
                case Key.F7:
                    return GraphicsFramework.Enum.EnumKeys.F7;
                case Key.F8:
                    return GraphicsFramework.Enum.EnumKeys.F8;
                case Key.F9:
                    return GraphicsFramework.Enum.EnumKeys.F9;
                case Key.F10:
                    return GraphicsFramework.Enum.EnumKeys.F10;
                case Key.F11:
                    return GraphicsFramework.Enum.EnumKeys.F11;
                case Key.F12:
                    return GraphicsFramework.Enum.EnumKeys.F12;
                case Key.F13:
                    return GraphicsFramework.Enum.EnumKeys.F13;
                case Key.F14:
                    return GraphicsFramework.Enum.EnumKeys.F14;
                case Key.F15:
                    return GraphicsFramework.Enum.EnumKeys.F15;
                case Key.F16:
                    return GraphicsFramework.Enum.EnumKeys.F16;
                case Key.F17:
                    return GraphicsFramework.Enum.EnumKeys.F17;
                case Key.F18:
                    return GraphicsFramework.Enum.EnumKeys.F18;
                case Key.F19:
                    return GraphicsFramework.Enum.EnumKeys.F19;
                case Key.F20:
                    return GraphicsFramework.Enum.EnumKeys.F20;
                case Key.F21:
                    return GraphicsFramework.Enum.EnumKeys.F21;
                case Key.F22:
                    return GraphicsFramework.Enum.EnumKeys.F22;
                case Key.F23:
                    return GraphicsFramework.Enum.EnumKeys.F23;
                case Key.F24:
                    return GraphicsFramework.Enum.EnumKeys.F24;

                //Default
                default:
                    return GraphicsFramework.Enum.EnumKeys.None;
            }

        }

        public override GraphicsFramework.Enum.EnumMouseButtons GetMouseButton(object e)
        {
            MouseEventArgs mouse = (MouseEventArgs)e;

            if (mouse.LeftButton == MouseButtonState.Pressed)
                return GraphicsFramework.Enum.EnumMouseButtons.LEFT;

            if (mouse.MiddleButton == MouseButtonState.Pressed)
                return GraphicsFramework.Enum.EnumMouseButtons.MIDDLE;

            if (mouse.RightButton == MouseButtonState.Pressed)
                return GraphicsFramework.Enum.EnumMouseButtons.RIGHT;

            return GraphicsFramework.Enum.EnumMouseButtons.NONE;
        }

        #endregion

        #region Property Conversion

        private Brush GetStroke(DrawProperty property)
        {
            return new SolidColorBrush(Color.FromArgb(property.LineColor.Alpha, property.LineColor.Red, property.LineColor.Green, property.LineColor.Blue));
        }

        private Brush GetBrush(DrawProperty property)
        {
            return new SolidColorBrush(Color.FromArgb(property.FillColor.Alpha, property.FillColor.Red, property.FillColor.Green, property.FillColor.Blue));
        }

        private Point[] GetPoints(IList<Point2F> points)
        {
            Point[] cpoint = new Point[points.Count];

            for (int count = 0; count < points.Count; count++)
                cpoint[count] = new Point(ToCoordX(points[count].X), ToCoordY(points[count].Y));

            return cpoint;
        }

        private Point GetPoint(Point2F point)
        {
            return new Point(ToCoordX(point.X), ToCoordY(point.Y));
        }

        private Point GetPoint(Point2I point)
        {
            return new Point(ToCoordX(point.X), ToCoordY(point.Y));
        }

        //private Font GetFont(TextProperty property)
        //{
        //    int style = 0;

        //    if (property.Bold)
        //        style += (int)FontStyle.Bold;

        //    if (property.Italic)
        //        style += (int)FontStyle.Italic;

        //    if (property.Underline)
        //        style += (int)FontStyle.Underline;

        //    if (property.StrikeOut)
        //        style += (int)FontStyle.Strikeout;

        //    Font font = new Font(property.Font, property.Size * zoomvalue, (FontStyle)style);

        //    return font;
        //}

        #endregion

        public override void BasicLine(DrawProperty property, Point2I point1, Point2I point2)
        {
            Line line = new Line();
            line.Stroke = GetStroke(property);
            line.StrokeThickness = GetLineWidth(property);

            line.X1 = point1.X;
            line.Y1 = point1.Y;
            line.X2 = point2.X;
            line.Y2 = point2.Y;

            graphics.Add(line);
        }

        public override void DrawLine(DrawProperty property, Point2F point1, Point2F point2)
        {
            throw new NotImplementedException();
        }

        public override void BasicRectangle(DrawProperty property, Point2I point, int width, int height)
        {
            Polygon rectangle = new Polygon();

            if (property.ShowOutline)
            {
                rectangle.StrokeThickness = GetLineWidth(property);
                rectangle.Stroke = GetStroke(property);
            }

            if (property.ShowFill)
                rectangle.Fill = GetBrush(property);

            float hwidth = width / 2;
            float hheight = height / 2;

            PointCollection points = new PointCollection();
            points.Add(new Point(point.X - hwidth, point.Y - hheight));
            points.Add(new Point(point.X - hwidth, point.Y + hheight));
            points.Add(new Point(point.X + hwidth, point.Y + hheight));
            points.Add(new Point(point.X + hwidth, point.Y - hheight));

            rectangle.Points = points;
            graphics.Add(rectangle);
        }

        public override void BasicRectangle(DrawProperty property, Point2F point, float width, float height)
        {
            Polygon rectangle = new Polygon();

            if (property.ShowOutline)
            {
                rectangle.StrokeThickness = GetLineWidth(property);
                rectangle.Stroke = GetStroke(property);
            }

            if (property.ShowFill)
                rectangle.Fill = GetBrush(property);

            float hwidth = width / 2;
            float hheight = height / 2;

            PointCollection points = new PointCollection();
            points.Add(new Point(point.X - hwidth, point.Y - hheight));
            points.Add(new Point(point.X - hwidth, point.Y + hheight));
            points.Add(new Point(point.X + hwidth, point.Y + hheight));
            points.Add(new Point(point.X + hwidth, point.Y - hheight));

            rectangle.Points = points;
            graphics.Add(rectangle);
        }

        public override void DrawRectangle(DrawProperty property, Point2I point, int width, int height)
        {
            Polygon rectangle = new Polygon();

            if (property.ShowOutline)
            {
                rectangle.StrokeThickness = GetLineWidth(property);
                rectangle.Stroke = GetStroke(property);
            }

            if (property.ShowFill)
                rectangle.Fill = GetBrush(property);

            Point cpoint = GetPoint(point);

            width *= Gridsize;
            height *= Gridsize;

            float hwidth = width / 2;
            float hheight = height / 2;

            PointCollection points = new PointCollection();
            points.Add(new Point(cpoint.X - hwidth, cpoint.Y - hheight));
            points.Add(new Point(cpoint.X - hwidth, cpoint.Y + hheight));
            points.Add(new Point(cpoint.X + hwidth, cpoint.Y + hheight));
            points.Add(new Point(cpoint.X + hwidth, cpoint.Y - hheight));

            rectangle.Points = points;
            graphics.Add(rectangle);
        }

        public override void DrawRectangle(DrawProperty property, Point2F point, float width, float height)
        {
            Polygon rectangle = new Polygon();

            if (property.ShowOutline)
            {
                rectangle.StrokeThickness = GetLineWidth(property);
                rectangle.Stroke = GetStroke(property);
            }

            if (property.ShowFill)
                rectangle.Fill = GetBrush(property);

            Point cpoint = GetPoint(point);

            width *= Gridsize;
            height *= Gridsize;

            float hwidth = width / 2;
            float hheight = height / 2;

            PointCollection points = new PointCollection();
            points.Add(new Point(cpoint.X - hwidth, cpoint.Y - hheight));
            points.Add(new Point(cpoint.X - hwidth, cpoint.Y + hheight));
            points.Add(new Point(cpoint.X + hwidth, cpoint.Y + hheight));
            points.Add(new Point(cpoint.X + hwidth, cpoint.Y - hheight));

            rectangle.Points = points;
            graphics.Add(rectangle);
        }

        public override void DrawCircle(DrawProperty property, Point2F point, float radius)
        {
        }

        public override void BasicEllipse(DrawProperty property, Point2I point1, Point2I point2)
        {
        }

        public override void DrawEllipse(DrawProperty property, Point2F point1, Point2F point2)
        {
        }

        public override void BasicEllipse(DrawProperty property, Point2I point, int width, int height)
        {
        }

        public override void DrawEllipse(DrawProperty property, Point2F point1, float width, float height)
        {
        }

        public override void DrawPolyline(DrawProperty property, IList<Point2F> points)
        {
        }

        public override void DrawPolygon(DrawProperty property, IList<Point2F> points)
        {
            Polygon rectangle = new Polygon();

            if (property.ShowOutline)
            {
                rectangle.StrokeThickness = GetLineWidth(property);
                rectangle.Stroke = GetStroke(property);
            }

            if (property.ShowFill)
                rectangle.Fill = GetBrush(property);

            Point[] cpoint = GetPoints(points);

            PointCollection colpoints = new PointCollection();

            foreach (Point item in cpoint)
            {
                colpoints.Add(new Point(item.X, item.Y));
            }

            rectangle.Points = colpoints;
            graphics.Add(rectangle);
        }

        public override void DrawText(DrawProperty property, TextProperty textproperty, Point2F point, string text)
        {
        }

        public override Point2I MeasureString(TextProperty textproperty, string text)
        {
            return new Point2I();
        }

        public override void BasicCircle(DrawProperty property, Point2I point, float radius)
        {
            throw new NotImplementedException();
        }

        public override void BasicCircle(DrawProperty property, Point2F point, float radius)
        {
            throw new NotImplementedException();
        }
    }
}
